using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Threading;

namespace CVS
{
    public class Server
    {

        public static int Main(string[] args)
        {
            TcpChannel channel;
            int port_number;
            int option_number;
            IRemoteServer iserver = null;
            RemoteServer server = new RemoteServer( );
            ObjRef objRef = new ObjRef( );

            port_number = -1;
            while (port_number == -1)
            {
                System.Console.WriteLine("Please insert server port: ");
                String port = System.Console.ReadLine();
                try
                {
                    port_number = Int32.Parse(port);
                }
                catch (System.FormatException e)
                {
                    System.Console.WriteLine("Invalid port number. \n" + e);
                    port_number = -1;
                }
            }

            //Create communication channel
            channel = new TcpChannel(port_number);
            ChannelServices.RegisterChannel(channel, true);

            option_number = -1;
            while (option_number == -1)
            {
                System.Console.WriteLine("Please choose server architecture: ");
                System.Console.WriteLine("1 - Centralized ");
                System.Console.WriteLine("2 - Replicated");
                String architecture = System.Console.ReadLine();
                try
                {
                    option_number = Int32.Parse(architecture);
                }
                catch (System.FormatException e)
                {
                    System.Console.WriteLine("Invalid option. \n" + e);
                    option_number = -1;
                }
                switch (option_number)
                {
                    case 1:
                        {
                            //Gets ip and port of current server
                            string enderecoTemp = ( (ChannelDataStore) channel.ChannelData ).ChannelUris[0];
                            char[] sep = { '/', '/' };
                            string[] enderecoTempArray = enderecoTemp.Split( sep );
                            string endereco = enderecoTempArray[2];

                            server.ServerType = "Centralized";
                            server.Address = endereco;

                            RemotingServices.Marshal( server, "MyRemoteServer" );
                        }
                        break;

                    case 2:
                        {
                            System.Console.WriteLine("Please insert main server address (type 'main' if this is the main server): ");
                            String mainServerIP = System.Console.ReadLine();

                            //Gets ip and port of current server
                            string addrTemp = ((ChannelDataStore)channel.ChannelData).ChannelUris[0];
                            char[] sep = { '/', '/' };
                            string[] addrTempArray = addrTemp.Split(sep);
                            string addr = addrTempArray[2];

                            RemotingServices.Marshal( server, "MyRemoteServer" );
                            
                            System.Console.WriteLine("Please insert k replication factor: ");
                            int kfactor = Int32.Parse(System.Console.ReadLine());

                            if (mainServerIP.Equals("main"))
                            {
                                //Initialiazes main server
                                server.InitializeServer("main", port_number, kfactor, null, addr);
                                //Add main server to list
                                server.AddServer(addr,0);
                            }
                            else
                            {
                                //Adds the replicate address to the main server list
                                IRemoteServer obj2 = (IRemoteServer)Activator.GetObject(typeof(IRemoteServer), "tcp://" + mainServerIP + "/MyRemoteServer");
                                obj2.AddServer(addr, 0);

                                //Initializes replicate server
                                server.InitializeServer("replicate", port_number, kfactor, mainServerIP, addr);
                            }

                            server.ServerType = "Replicated";
                        }
                        break;

                    default:
                        System.Console.WriteLine("Invalid option. \n");
                        option_number = -1;
                        break;
                }
            }

            while (true)
            {
                System.Console.WriteLine("Please insert command: ");
                String option = System.Console.ReadLine();

                String[] command = option.Split(' ');

                string firstCommand = command[0];
                string secondCommand = null;
                if(command.Length == 2)
                    secondCommand = command[1];

                if ( firstCommand.CompareTo( "print" ) == 0 )
                {
                    if ( iserver != null )
                        iserver.Print( );
                }
                else if ( firstCommand.CompareTo( "hold" ) == 0 )
                {
                    channel.StopListening( null );
                    //RemotingServices.Disconnect( server );
                }
                else if ( firstCommand.CompareTo( "resume" ) == 0 )
                {
                    channel.StartListening( null );
                    //RemotingServices.Marshal( server, "MyRemoteServer" );
                }
                else if ( firstCommand.CompareTo( "load" ) == 0 )
                {
                    if ( iserver != null )
                        iserver.Load( secondCommand );
                }
                else if (firstCommand.CompareTo("exit") == 0)
                {
                    break;
                }
            }

            return 0;
        }
    }
}
